package bebetes;

import java.awt.Color;
import java.util.ArrayList;
import java.util.List;
import util.DistancesEtDirections;
import visu.Dirigeable;
import visu.Positionnable;

/**
 * Bébête de type émergente.
 * 
 * Ce type de bébêtes ont le comportement suivant :
 * <ul>
 * <li>Essaye d'aller à la vitesse moyenne des bébêtes autour</li>
 * <li>Va dans la direction moyenne du troupeau environnant (les bébêtes autour)
 * </li>
 * <li>Maintient une distance minimale avec celles qui sont autour</li>
 * </ul>
 * 
 * @author COLLET Philippe
 * @author gnpt
 */
public class BebeteEmergente extends Bebete {
	/** Distance minimale entre deux bébête en pixels */
	public static final float distanceMin = 10f;
	private float distancePlusProche = Float.MAX_VALUE;

	/**
	 * Constructeur par défaut.
	 * 
	 * @param c
	 *            le champs sur lequel se déplace la bébête.
	 * @param x
	 *            l'abscisse de la bébête sur le champs.
	 * @param y
	 *            l'ordonnée de la bébête sur le champs.
	 * @param dC
	 *            la direction courante de la bébête.
	 * @param vC
	 *            la vitesse courante de la bébête.
	 * @param col
	 *            la couleur associée à la bébête.
	 */
	public BebeteEmergente(ChampDeBebetes c, int x, int y, float dC, float vC,
			Color col) {
		super.champ = c;
		super.x = x;
		super.y = y;
		super.directionCourante = dC;
		super.vitesseCourante = vC;
		super.couleur = col;
	}

	@Override
	public void calculeDeplacementAFaire() {
		// calcul des vitesses et directions moyennes, calcul de la distance par
		// rapport à la bébête la plus proche
		float vit = super.vitesseCourante;
		float dir = super.directionCourante;
		double plusPetiteDistance = Double.MAX_VALUE;

		List<? extends Dirigeable> betesVues = filtreDirigeables(super
				.getChosesVues());

		for (Dirigeable p : betesVues) {
			vit += p.getVitesseCourante();
			dir += p.getDirectionCourante();
			plusPetiteDistance = Math.min(plusPetiteDistance,
					DistancesEtDirections.distanceDepuisUnPoint(super.x,
							super.y, p.getX(), p.getY()));
		}

		// Vitesse minimale = 2
		this.vitesseCourante = Math.max(vit / (betesVues.size() + 1), 1);
		this.directionCourante = dir / (betesVues.size() + 1);
		this.distancePlusProche = (float) plusPetiteDistance;
	}

	/**
	 * Pas vraiment de covariance, donc on est obligé de filtrer la liste pour
	 * savoir ce qui remue de ce qui est potentiellement fixe...
	 */
	protected static List<? extends Dirigeable> filtreDirigeables(
			List<? extends Positionnable> lp) {
		ArrayList<Dirigeable> output = new ArrayList<Dirigeable>();
		for (Positionnable p : lp) {
			if (p instanceof Dirigeable)
				output.add((Dirigeable) p);
		}
		return output;
	}

	@Override
	public void effectueDeplacement() {
		super.x += Math.round((this.vitesseCourante * Math
				.cos((double) super.directionCourante)));
		super.y += Math.round((this.vitesseCourante * Math
				.sin((double) super.directionCourante)));
		super.x %= super.champ.getLargeur();
		super.y %= super.champ.getHauteur();
		if (super.x < 0) {
			super.x += super.champ.getLargeur();
		}
		if (super.y < 0) {
			super.y += super.champ.getHauteur();
		}
	}

	/**
	 * Redéfinition de l'action pour ne pas se déplacer si la bébête est trop
	 * proche d'une autre bébête.
	 */
	@Override
	public void agit() {
		this.calculeDeplacementAFaire();
		if (this.distancePlusProche >= distanceMin) {
			this.effectueDeplacement();
		}
	}

}
